﻿using System;
using System.Text;
using System.Threading;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Collections.Generic;
using Microsoft.Reputation.Services;


namespace Microsoft.Reputation.Tests.FrontEndCommon
{
    [Serializable]
    public class MrsDeliveryServiceProvider
    {
        #region Delivery service connection data members
        [NonSerialized]
        private MrsDeliveryServiceClient serviceClient;
        [NonSerialized]
        private ClientIdToken clientToken;
        [NonSerialized]
        private StateToken stateToken;
        private long overrideStamp;
        private uint delayCommMins;
        private uint operStatus;
        private string deliveryServiceURL;
        #endregion

        #region Properties

        public StateToken StTok
        {
            get
            {
                return stateToken;
            }
        }

        public long OverrideStamp
        {
            get
            {
                return overrideStamp;
            }

            set
            {
                overrideStamp = value;
            }
        }

        public uint DelayCommMins
        {
            get
            {
                return delayCommMins;
            }
        }

        public uint OperationStatus
        {
            get
            {
                return operStatus;
            }
        }

        #endregion

        /// <summary>
        /// Constructs a MrsDeliveryServiceProvider object using ClientIdToken and the delivery service URL
        /// Throws ArgumentNullException if the Delivery Service URL is null
        /// </summary>
        /// <param name="token"></param>
        /// <param name="serviceURL"></param>
        public MrsDeliveryServiceProvider(ClientIdToken token, string serviceURL)
        {
            clientToken = token;
            if (serviceURL == null)
            {
                throw new ArgumentNullException("ServiceURL", "Cannot connect with a null URL.");
            }
            deliveryServiceURL = serviceURL;
            serviceClient = new MrsDeliveryServiceClient(this.CreateBinding(), new EndpointAddress(deliveryServiceURL));
        }

        public MrsDeliveryServiceProvider(Guid customerId, string customerVersion, Guid deploymentId, Guid clientId, string serviceURL)
            : this(new ClientIdToken() 
            {
                CustomerId = customerId, 
                CustomerVersion = customerVersion,
                DeploymentId = deploymentId,
                ClientId = clientId
            }, 
            serviceURL)
        {
        }


        public MrsDeliveryServiceProvider(string serviceURL)
            : this(Guid.NewGuid(), "Test Code: MrsDeliveryServiceProvider", Guid.NewGuid(), Guid.NewGuid(), serviceURL)
        {
        }

        /// <summary>
        /// Helper method to create delivery service connection binding.
        /// </summary>
        /// <returns></returns>
        private Binding CreateBinding()
        {
            BasicHttpBinding binding = new BasicHttpBinding();

            binding.MaxReceivedMessageSize = 16777216;
            binding.SendTimeout = new TimeSpan(2, 0, 0);
            binding.ReceiveTimeout = new TimeSpan(2, 0, 0);

            if (this.deliveryServiceURL.StartsWith("https:"))
            {
                binding.Security.Mode = BasicHttpSecurityMode.Transport;
            }
            else
            {
                binding.Security.Mode = BasicHttpSecurityMode.None;
            }

            return binding;
        }

        /// <summary>
        /// Helper method to reset the delivery service provider state to default
        /// </summary>
        public void ClearStatus()
        {
            stateToken = null;
            this.overrideStamp = 0;
            this.operStatus = 0;
            this.delayCommMins = 0;
        }

        /// <summary>
        /// Takes the Lookup requests from test code, converts it to delivery service lookup requests and calls the web service API
        /// for lookup.
        /// </summary>
        /// <param name="requests">List of test MrsLookupRequest objects</param>
        /// <param name="filter">Filter used as global filter for all lookup requests in the list</param>
        /// <param name="results">List of test MrsLookupResponse objects, one per request</param>
        /// <returns>Status whether the lookup call to the web service was successful or not. True, if success, else False</returns>
        public bool LookupObjectAPI(IList<MrsLookupRequest> requests, MrsFilter filter, out IList<MrsLookupResponse> results)
        {
            return LookupObjectAPI(requests, filter, out results, 0);
        }

        /// <summary>
        /// Takes the Lookup requests from test code, converts it to delivery service lookup requests and calls the web service API
        /// for lookup.
        /// </summary>
        /// <param name="requests">List of test MrsLookupRequest objects</param>
        /// <param name="filter">Filter used as global filter for all lookup requests in the list</param>
        /// <param name="results">List of test MrsLookupResponse objects, one per request</param>
        /// <param name="overrideStamp">If set to more than 1, returns the override data</param>
        /// <returns>Status whether the lookup call to the web service was successful or not. True, if success, else False</returns>
        public bool LookupObjectAPI(IList<MrsLookupRequest> requests, MrsFilter filter, out IList<MrsLookupResponse> results, long stamp)
        {
            ClearStatus();
            results = null;
            LookupRequest[] apiRequests = null;
            LookupResponse[] apiResponses = null;
            Filter apiFilter = null;

            if (requests != null)
            {
                apiRequests = new LookupRequest[requests.Count];
                for (int idx = 0; idx < requests.Count; idx++)
                {
                    apiRequests[idx] = MrsObjectConverter.Convert(requests[idx]);
                }
            }

            if (filter != null)
            {
                apiFilter = MrsObjectConverter.Convert(filter);
            }

            StateToken apiStateToken = this.stateToken;
            long apiOverrideStamp = stamp;
            uint apiDelayCommMins;
            uint apiOperStatus;

            apiResponses = this.serviceClient.LookupObjects(clientToken, apiRequests, apiFilter, ref apiStateToken, ref apiOverrideStamp, out apiDelayCommMins, out apiOperStatus);

            if (apiResponses != null)
            {
                results = new List<MrsLookupResponse>();
                for (int idx = 0; idx < apiResponses.Length; idx++)
                {
                    if (apiResponses[idx] != null)
                    {
                        results.Add(MrsObjectConverter.Convert(apiResponses[idx]));
                    }
                }
            }

            stateToken = apiStateToken;
            overrideStamp = apiOverrideStamp;
            delayCommMins = apiDelayCommMins;
            operStatus = apiOperStatus;

            return (apiOperStatus == StatusCodes.OK);
        }

        public CategoryReputation[] LookupCategoriesForUrlAPI(string url)
        {
            ClearStatus();
            uint apiOperStatus;
            CategoryReputation[] catRep = this.serviceClient.LookupCategoriesForUrl(out apiOperStatus, clientToken, url);

            operStatus = apiOperStatus;
            return catRep;
        }
    }
}
